﻿using System;
using System.Xml;
using FluentNHibernate;
using FluentNHibernate.Mapping;
using NotMyself.Oxite.Data.LinqToNHibernateProvider.Tests.Properties;

namespace NotMyself.Oxite.Data.LinqToNHibernateProvider.Tests.Utility
{
    public class ClassMapTester<T>
    {
        protected XmlElement currentElement;
        protected XmlDocument document;
        protected XmlNamespaceManager mgr;


        public ClassMapTester<T> ForString(string input)
        {
            document = new XmlDocument();
            document.LoadXml(input);
            return For(document);
        }

        public ClassMapTester<T> For(XmlDocument doc)
        {
            document = doc;
            SetNameSpaceManager();
            return this;
        }

        public ClassMapTester<T> For<A>() where A : ClassMap<T>, new()
        {
            For(new A().CreateMapping(new MappingVisitor()));
            return this;
        }

        private void SetNameSpaceManager()
        {
            mgr = new XmlNamespaceManager(new NameTable());
            mgr.AddNamespace("urn", "urn:nhibernate-mapping-2.2");
        }

        public ClassMapTester<T> Element(string elementPath)
        {
            if (document.DocumentElement != null)
                currentElement = (XmlElement) document.DocumentElement.SelectSingleNode(elementPath, mgr);

            return this;
        }


        public ClassMapTester<T> HasAttribute(string name, string value)
        {
            currentElement.AttributeShouldEqual(name, value);

            return this;
        }

        public ClassMapTester<T> DoesntHaveAttribute(string name)
        {
            currentElement.HasAttribute(name).ShouldBeFalse();

            return this;
        }

        public ClassMapTester<T> Exists()
        {
            currentElement.ShouldNotBeNull();

            return this;
        }

        public ClassMapTester<T> DoesntExist()
        {
            currentElement.ShouldBeNull();

            return this;
        }

        public ClassMapTester<T> HasName(string name)
        {
            currentElement.Name.ShouldEqual(name);

            return this;
        }

        public ClassMapTester<T> HasInnerText(string value)
        {
            currentElement.InnerText.ShouldEqual(value);

            return this;
        }

        public ClassMapTester<T> TestDefaultConventions()
        {
            return Element("/urn:hibernate-mapping").Exists()
                .HasAttribute("default-lazy", "true")
                .Element("/urn:hibernate-mapping/class").Exists()
                .HasAttribute("name", typeof (T).Name)
                .HasAttribute("table", "oxite_" + typeof (T).Name)
                .HasAttribute("proxy", typeof (T).GetInterfaces()[0].AssemblyQualifiedName)
                .Element("/urn:hibernate-mapping/class/id").Exists()
                .HasAttribute("column", typeof (T).Name + "ID")
                .HasAttribute("type", "Guid")
                .Element("/urn:hibernate-mapping/class/id/generator").Exists()
                .HasAttribute("class", "guid");
        }

        public ClassMapTester<T> TestProperty<A>(params string[] args)
        {
            string query;
            switch (typeof (A).Name)
            {
                case "String":
                    query = String.Format(Resources.stringProperty, args);
                    break;
                default:
                    query = String.Format(Resources.baseProperty, args);
                    break;
            }


            return Element(query);
        }
    }
}